什么是Describer

Describer是Kubectl上用来描述对象具体信息的,和kubectl describe配合使用。

在/pkg/kubectl/cmd/util/factory.go中,有Describer()函数,可以依据mapping生成合适的Describer。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func (f *factory) Describer(mapping *meta.RESTMapping) (kubectl.Describer, error) {
mappingVersion := mapping.GroupVersionKind.GroupVersion()
if mapping.GroupVersionKind.Group == federation.GroupName {
fedClientSet, err := f.clients.FederationClientSetForVersion(&mappingVersion)
if err != nil {
return nil, err
}
if mapping.GroupVersionKind.Kind == "Cluster" {
return &kubectl.ClusterDescriber{Interface: fedClientSet}, nil
}
}
clientset, err := f.clients.ClientSetForVersion(&mappingVersion)
if err != nil {
return nil, err
}
//***找到合适的describer***//
if describer, ok := kubectl.DescriberFor(mapping.GroupVersionKind.GroupKind(), clientset); ok {
return describer, nil
}
return nil, fmt.Errorf("no description has been implemented for %q", mapping.GroupVersionKind.Kind)
}

Describer

Describer定义在/pkg/kubectl/describe.go中:

1
2
3
4
5
6
// Describer generates output for the named resource or an error
// if the output could not be generated. Implementers typically
// abstract the retrieval of the named object from a remote server.
type Describer interface {
Describe(namespace, name string, describerSettings DescriberSettings) (output string, err error)
}

可以看到,只要实现了Describe()的结构体都可以称为Describer。

所以,在/pkg/kubectl/describer.go中,实现了PodDescriber, ReplicationControllerDescriber, SecretDescriber, ServiceDescriber, ServiceAccountDescriber, NodeDescriber, LimitRangeDescriber, ResourceQuotaDescriber, PersistentVolumeDescriber, PersistentVolumeClaimDescriber, NamespaceDescriber, EndpointsDescriber, ConfigMapDescriber, ReplicaSetDescriber, HorizontalPodAutoscalerDescriber, NetworkPolicyDescriber, HorizontalPodAutoscalerDescriber, DaemonSetDescriber, DeploymentDescriber, JobDescriber, IngressDescriber, JobDescriber, CronJobDescriber, StatefulSetDescriber, CertificateSigningRequestDescriber, StorageClassDescriber, PodDisruptionBudgetDescriber。

在实现Describer的结构体中,通常会嵌入一个clientset,用来在Describe()中获取具体的Object。比如说下面的ReplicationControllerDescriber。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// ReplicationControllerDescriber generates information about a replication controller
// and the pods it has created.
type ReplicationControllerDescriber struct {
clientset.Interface
}
func (d *ReplicationControllerDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
rc := d.Core().ReplicationControllers(namespace)
pc := d.Core().Pods(namespace)
controller, err := rc.Get(name)
if err != nil {
return "", err
}
running, waiting, succeeded, failed, err := getPodStatusForController(pc, labels.SelectorFromSet(controller.Spec.Selector))
if err != nil {
return "", err
}
var events *api.EventList
if describerSettings.ShowEvents {
events, _ = d.Core().Events(namespace).Search(controller)
}
return describeReplicationController(controller, events, running, waiting, succeeded, failed)
}

DescriberMap

DescriberMap中记录了GK和Describer的关系。这里使用GK作为Key,因为GK足以标记一个类型。目前还不支持同名Kind出现在不同的Group(internal除外)中(否则resource无法找到合适的GVK),所以感觉完全可以仅使用Kind作为Key。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//***构建Describer map,其中key为GK,value为Describer***//
func describerMap(c clientset.Interface) map[unversioned.GroupKind]Describer {
m := map[unversioned.GroupKind]Describer{
api.Kind("Pod"): &PodDescriber{c},
api.Kind("ReplicationController"): &ReplicationControllerDescriber{c},
api.Kind("Secret"): &SecretDescriber{c},
api.Kind("Service"): &ServiceDescriber{c},
api.Kind("ServiceAccount"): &ServiceAccountDescriber{c},
api.Kind("Node"): &NodeDescriber{c},
api.Kind("LimitRange"): &LimitRangeDescriber{c},
api.Kind("ResourceQuota"): &ResourceQuotaDescriber{c},
api.Kind("PersistentVolume"): &PersistentVolumeDescriber{c},
api.Kind("PersistentVolumeClaim"): &PersistentVolumeClaimDescriber{c},
api.Kind("Namespace"): &NamespaceDescriber{c},
api.Kind("Endpoints"): &EndpointsDescriber{c},
api.Kind("ConfigMap"): &ConfigMapDescriber{c},
extensions.Kind("ReplicaSet"): &ReplicaSetDescriber{c},
extensions.Kind("HorizontalPodAutoscaler"): &HorizontalPodAutoscalerDescriber{c},
extensions.Kind("NetworkPolicy"): &NetworkPolicyDescriber{c},
autoscaling.Kind("HorizontalPodAutoscaler"): &HorizontalPodAutoscalerDescriber{c},
extensions.Kind("DaemonSet"): &DaemonSetDescriber{c},
extensions.Kind("Deployment"): &DeploymentDescriber{c},
extensions.Kind("Job"): &JobDescriber{c},
extensions.Kind("Ingress"): &IngressDescriber{c},
batch.Kind("Job"): &JobDescriber{c},
batch.Kind("CronJob"): &CronJobDescriber{c},
apps.Kind("StatefulSet"): &StatefulSetDescriber{c},
certificates.Kind("CertificateSigningRequest"): &CertificateSigningRequestDescriber{c},
storage.Kind("StorageClass"): &StorageClassDescriber{c},
policy.Kind("PodDisruptionBudget"): &PodDisruptionBudgetDescriber{c},
}
return m
}

Describer的入口

最后来看下Describer的入口。

之前我们看到,可以使用下面的代码获取Describer

1
2
3
4
//***找到合适的describer***//
if describer, ok := kubectl.DescriberFor(mapping.GroupVersionKind.GroupKind(), clientset); ok {
return describer, nil
}

所以来看来/pkg/kubectl/describe.go中的DescriberFor()函数:

1
2
3
4
5
//***返回合适的describer***//
func DescriberFor(kind unversioned.GroupKind, c clientset.Interface) (Describer, bool) {
f, ok := describerMap(c)[kind]
return f, ok
}

函数的实现很简单,先调用describerMap()生成DescriberMap,然后找到对应kind的Describer。